import EventEmitter from "events";
import http from "http";
import context from "./context.js";
import request from "./request.js";
import response from "./response.js";
import Stream from 'stream'
export default class Application extends EventEmitter {
  constructor() {
    super();
    // 对应用之间形成了隔离
    // this.context.__proto__ == context
    this.context = Object.create(context);
    this.request = Object.create(request);
    this.response = Object.create(response);
    this.middlewares = [];
  }
  use(middleware) {
    this.middlewares.push(middleware);
  }
  createCtx(req, res) {
    let context = Object.create(this.context);
    let request = Object.create(this.request);
    let response = Object.create(this.response);
    context.req = req;
    context.res = res;
    context.request = request;
    context.response = response;
    context.request.req = req;
    context.response.res = res;
    // context 可以有代理
    return context;
  }
  compose(ctx) {
    let middlewares = this.middlewares;
    let index = -1;
    function dispatch(i) {
      if (i === middlewares.length) return Promise.resolve();

      if (i === index)
        return Promise.reject(new Error("next() called multiple times"));
      index = i;

      let fn = middlewares[i];
      // await () => dispatch(i + 1))  ==  next
      try {
        return Promise.resolve(fn(ctx, () => dispatch(i + 1)));
      } catch (e) {
        return Promise.reject(e);
      }
    }
    return dispatch(0);
  }
  handleRequest = (req, res) => {
    // req, res  -> ctx
    // ctx.request  ctx.response
    //  每次请求都产生一个新的 上下文，  因为http请求是独立的

    const ctx = this.createCtx(req, res);
    res.statusCode = 404;

    this.compose(ctx)
      .then(() => {
        if (ctx.body instanceof Stream){
          ctx.body.pipe(res);
        }else if (ctx.body) {
            res.end(ctx.body);
          } else {
            res.end("Not Found");
          }
      })
      .catch((e) => {
        this.emit("error", e);
      });
    // this.fn(ctx); // 执行用户的逻辑
  };
  listen(...args) {
    const server = http.createServer(this.handleRequest);
    server.listen(...args);
  }
}

export { EventEmitter };
